package br.ufsc.ctc.ine5622.compilador.lex;

import java.util.LinkedList;


import br.ufsc.ctc.ine5622.compilador.semantico.Simbolo;
import br.ufsc.ctc.ine5622.compilador.semantico.DeclarationAnalysis;
import br.ufsc.ctc.ine5622.compilador.semantico.Simbolo.ColunaKey;

public class Semantico implements Constants{
	
	public enum Categoria {
		ID_PROGRAMA,
		CONSTANTE,
		VARIAVEL,
		PROCEDIMENTO,
		FUNCAO,
		PARAMETRO
		
	}
	
	public enum TipoConstante{
		INTEIRO, REAL, LITERAL, FALSO, VERDADEIRO
	}
	
	public enum TipoVariavel{
		INTEIRO, REAL, LITERAL, BOOLEANO, CADEIA, VETOR
	}
	
	public enum ContextLid{
		DECL, PAR_FORMAIS, LEITURA
	}
	
	public enum ContextExpr{
		IMPRESSAO, PAR_ATUAL	
	}
	
	public enum MpPar {
		REFERENCIA, VALOR
	}
	
	public enum Operador{
		MAIS, MENOS, ESTRELA, BARRA, E, OU, DIV, IGUAL, MAIOR_QUE, MENOR_QUE, MAIOR_IGUAL, MENOR_IGUAL, DIFERENTE
	}
	
	/**
	 * Tabela de simbolos. 
	 */
	private LinkedList<Simbolo> tabelaSimbolos = new LinkedList<Simbolo>();
	
	/**
	 * Nível de escopo léxico.
	 */
	private Integer nivelAtual = 0;
	
	/**
	 * Classe que implementa todos os métodos de regras de análise semântica.
	 */
	private DeclarationAnalysis declAnalysis;
	
	/**
	 * Flag para o ligamento da análise semântica.
	 */
	private boolean ligado = true;
	
	public Semantico(){
		declAnalysis = new DeclarationAnalysis(this);
	}
	
	 /**
     * Liga ou desliga a analise semantica.
     * @param ligado
     */
    public void setLigado(boolean ligado){
    	this.ligado = ligado;
    }

    /**
     * Insere na tabela de simbolos um simbolo.
     * @param simbolo
     */
	public void putOnTabelaSimbolos(Simbolo simbolo) {
		tabelaSimbolos.add(simbolo);
	}

	public LinkedList<Simbolo> getTabelaSimbolos(){
		return tabelaSimbolos;
	}
	
	public int getNivelAtual() {
		return nivelAtual;
	}

	public void incrementaNivelAtual(){
		nivelAtual++;
	}
	
	public void decrementaNivelAtual(){
		nivelAtual--;
	}
	
	/**
	 * Remove da tabela de simbolos todos os simbolos de um determinado nível.
	 * @param nivel
	 */
	public void removeNivel(Integer nivel){
		LinkedList<Simbolo> removeList = new LinkedList<Simbolo>();
		for(Simbolo a: tabelaSimbolos){
			if(nivel.equals(a.getColunas().get(ColunaKey.NIVEL))){
				removeList.add(a);
			}
		}
		tabelaSimbolos.removeAll(removeList);
	}
	
	/**
	 * Retorna um simbolo da tabela de simbolos pelo seu nome. 
	 * @param name
	 * @return
	 */
	public Simbolo findAtributoByName(String name){
		for(Simbolo a: tabelaSimbolos){
			if(a.getNome().equals(name)){
				return a;
			}
		}
		return null;
	}
	
	/**
	 * Seta o valor de uma coluna para uma linha na tabela de simbolos.
	 * @param linha
	 * @param colunaNome
	 * @param valor
	 */
	public void setColuna(int linha, ColunaKey colunaNome, Object valor){
		tabelaSimbolos.get(linha).getColunas().put(colunaNome, valor);
	}

	/**
	 * Imprime em std out uma representação textual da tabela de simbolos.
	 */
	public void printTable() {
		for(Simbolo a: tabelaSimbolos){
			System.out.println("------");
			System.out.println(a);
		}
	}
	
	
	/**
	 * Traduz para Integer a string que representa inteiro em LSI.
	 * @param lexeme
	 * @return
	 */
	public static Integer traduzInteiro(String lexeme){
		lexeme.toUpperCase();
		int eIndex = lexeme.lastIndexOf("E");
		if(eIndex < 0){
			return Integer.parseInt(lexeme);
		}else{
			int mantissa = Integer.parseInt(lexeme.substring(0, eIndex));
			int expoente = Integer.parseInt(lexeme.substring(eIndex +1));
			return mantissa * (int) Math.pow(10, expoente);
		}
	}
	/**
	 * traduz para Double a string que representa real em LSI.
	 * @param lexeme
	 * @return
	 */
	public static Double traduzReal(String lexeme){
		lexeme.toUpperCase();
		return Double.parseDouble(lexeme);
	}

	
	/**
	 * Executa ação.
	 * @param action
	 * @param token
	 * @throws SemanticError
	 */
    public void executeAction(int action, Token token)	throws SemanticError{
    	if(ligado == false){
    		return;
    	}
        switch(action){
        case 1:
        	declAnalysis.programa(token);
        	break;
        case 2:
        	declAnalysis.constId(token);
        	break;
        case 3:
        	declAnalysis.constVal(token);
        	break;
        case 4:
        	declAnalysis.declLidInicio(token);
        	break;
        case 5:
        	declAnalysis.declLidFim(token);
        	break;
        case 6:
        	declAnalysis.varsTipo(token);
        	break;
        case 7:
        	declAnalysis.procId(token);
        	break;
        case 8:
        	declAnalysis.funcaoId(token);
        	break;
        case 9:
        	declAnalysis.setaNumParFormais(token);
        	break;
        case 10:
        	declAnalysis.setaTipoRetorno(token);
        	break;
        case 11:
        	declAnalysis.cleanScope(token);
        	break;
        case 12:
        	declAnalysis.parFormaisLidInicio(token);
        	break;
        case 13:
        	declAnalysis.parFormaisLidFim(token);
        	break;
        case 14:
        	declAnalysis.parFormaisTipo(token);
        	break;
        case 15:
        	declAnalysis.setMpParRef(token);
        	break;
        case 16:
        	declAnalysis.setMpParVal(token);
        	break;
        case 17:
        	declAnalysis.id(token);
        	break;
        case 18:
        	declAnalysis.cadeiaConstante(token);
        	break;
        case 19:
        	declAnalysis.vetorDimensao1(token);
        	break;
        case 20:
        	declAnalysis.vetorSetDim2(token);
        	break;
        case 21:
        	declAnalysis.vetorTipo(token);
        	break;
        case 22:
        	declAnalysis.checaDimensaoLimite1(token);
        	break;
        case 23:
        	declAnalysis.checaDimensaoLimite2(token);
        	break;
        case 24:
        	declAnalysis.vetorDimensao2(token);
        	break;
        case 25:
        	declAnalysis.constanteId(token);
        	break;
        case 26:
        	declAnalysis.tipoInteiro(token);
        	break;
        case 27:
        	declAnalysis.tipoReal(token);
        	break;
        case 28:
        	declAnalysis.tipoBooleano(token);
        	break;
        case 29:
        	declAnalysis.tipoCaracter(token);
        	break;
        case 30:
        	declAnalysis.comandoId(token);
        	break;
        case 31:
        	declAnalysis.checaTipoExpIntBool(token);
        	break;
        case 32:
        	declAnalysis.checaIdPara(token);
        	break;
        case 33:
        	declAnalysis.checaTipoExprPara(token);
        	break;
        case 34:
        	declAnalysis.setaContextoLeitura(token);
        	break;
        case 35:
        	declAnalysis.setaContextExcrita(token);
        	break;
        case 36:
        	declAnalysis.checaIdAssociacao(token);
        	break;
        case 37:
        	declAnalysis.checaTipoLadoDireitoAssociacao(token);
        	break;
        case 38:
        	declAnalysis.checaIdAcessoArray(token);
        	break;
        case 39:
        	declAnalysis.checaIndicesArray(token);
        	break;
        case 40:
        	declAnalysis.checaIndicesSegundosArray(token);
        	break;
        case 41:
        	declAnalysis.checaIdChamadaFuncao(token);
        	break;
        case 42:
        	declAnalysis.checaParametrosFuncao(token);
        	break;
        case 43:
        	declAnalysis.checaNumeroParFormais(token);
        	break;
        case 44:
        	declAnalysis.checaIdProcedure(token);
        	break;
        case 45:
        	declAnalysis.expressao2(token);
        	break;
        case 46:
        	declAnalysis.repExpr(token);
        	break;
        case 47:
        	declAnalysis.setaTipoExpr(token);
        	break;
        case 48:
        	declAnalysis.exprSimplesRestoExpr(token);
        	break;
        case 49:
        	declAnalysis.setaIgual(token);
        	break;
        case 50:
        	declAnalysis.setaMenorQue(token);
        	break;
        case 51:
        	declAnalysis.setaMaiorQue(token);
        	break;
        case 52:
        	declAnalysis.setaMaiorIgual(token);
        	break;
        case 53:
        	declAnalysis.setaMenorIgual(token);
        	break;
        case 54:
        	declAnalysis.setaDiferente(token);
        	break;
        case 55:
        	declAnalysis.setaTipoExprSimples(token);
        	break;
        case 56:
        	declAnalysis.checaValidadeOperadorAdd(token);
        	break;
        case 57:
        	declAnalysis.checaCompatibilidadeTipoTermo(token);
        	break;
        case 58:
        	declAnalysis.setaMais(token);
        	break;
        case 59:
        	declAnalysis.setaMenos(token);
        	break;
        case 60:
        	declAnalysis.setaOu(token);
        	break;
        case 61:
        	declAnalysis.setaTipoTermo(token);
        	break;
        case 62:
        	declAnalysis.checaAplicabilidaddeOperadorTipoTermo(token);
        	break;
        case 63:
        	declAnalysis.checaCompatibilidadeTipoFator(token);
        	break;
        case 64:
        	declAnalysis.setaEstrela(token);
        	break;
        case 65:
        	declAnalysis.setaBarra(token);
        	break;
        case 66:
        	declAnalysis.setaDiv(token);
        	break;
        case 67:
        	declAnalysis.setaE(token);
        	break;
        case 68:
        	declAnalysis.checkNegacao(token);
        	break;
        case 69:
        	declAnalysis.checkTipoFatorBool(token);
        	break;
        case 70:
        	declAnalysis.checkOpUnitario(token);
        	break;
        case 71:
        	declAnalysis.checkTipoFatorAdicao(token);
        	break;
        case 72:
        	declAnalysis.resetaOperadoresFator(token);
        	break;
        case 73:
        	declAnalysis.setaTipoExpFator(token);
        	break;
        case 74:
        	declAnalysis.setaTipoVarFator(token);
        	break;
        case 75:
        	declAnalysis.setaTipoCteFator(token);
        	break;
        case 76:
        	declAnalysis.checaCategoriaIdFuncao(token);
        	break;
        case 77:
        	declAnalysis.checaNpaNpf(token);
        	break;
        case 78:
        	declAnalysis.regra78(token);
        	break;
        case 79:
        	declAnalysis.regra79(token);
        	break;
        case 80:
        	declAnalysis.regra80(token);
        	break;
        case 81:
        	declAnalysis.setaConstanteInteiro(token);
        	break;
        case 82:
        	declAnalysis.setaConstanteReal(token);
        	break;
        case 83:
        	declAnalysis.setaConstanteFalso(token);
        	break;
        case 84:
        	declAnalysis.setaConstanteVerdadeiro(token);
        	break;
        case 85:
        	declAnalysis.setaConstanteLiteral(token);
        	break;
        }
    }

   
    
    
}
